#include "Renderer.h"
#include "HUDManager.h"


Renderer* Renderer::instance = NULL;

Renderer::Renderer(Window &parent) : OGLRenderer(parent)	{	


	bloomScale = 0.05f;
    bloomBlurRadius = 64.0f;
	flareScale = 0.05f;
	flareBlurRadius = 24.0f;


	camera = NULL;
	root = new SceneNode();
	instance = this;

	angle = 0;

	basicFont =  new Font(SOIL_load_OGL_texture(TEXTUREDIR"tahoma.tga",SOIL_LOAD_AUTO,SOIL_CREATE_NEW_ID,SOIL_FLAG_COMPRESS_TO_DXT),16,16);

	glEnable(GL_DEPTH_TEST);

	//only if all the initialization is successful, the initialization will be initialized
	init = InitializeShaders() ;
	init *= GenerateShadowBuffer();
	init *= InitializeWorldLight();
	cout << init << endl;
	//create buffer for blur
	InitBuffers();
	//create buffer for lensflare
	InitializeLensFlareBuffer();
	//create waves;
	wavesQuad = new WavesMesh();
	wavesQuad->SetTexture(SOIL_load_OGL_texture(TEXTUREDIR"water1.jpg", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, 0));
	SetTextureRepeating(wavesQuad->GetTexture(),true);
	Density = 3;
	fogColor = Vector4(0.7f, 0.7f, 0.7f, 1.0f);
	isFog = false;
}

Renderer::~Renderer(void)	{
	delete root;
	//delete all the shaders
	for (unsigned int i = 0; i < MAXSHADERCOUNT; ++i)
	{
		delete shaders[i];
	}
	shaders.clear();

	if (worldLight)
		delete worldLight;

	currentShader = NULL;

	delete sphere;
	delete quad;
	delete wavesQuad;
	glDeleteTextures(3, bufferColourTex);
	glDeleteTextures(3, bufferDepthTex);
	glDeleteFramebuffers(3, bufferFBO);
}

/* Method used to initialize the world light inlcuding the sphere that indicates the sun.
* Return: boolean type that shows if initialization is successful
* Parameters: None
* Author: Kan Tang
*/
bool Renderer::InitializeWorldLight()
{
	worldLight = new Light(WORLD_LIGHT_STARTING_POSITION, Vector4(1, 1, 1, 1), 100000.0f);
	sphere = new OBJMesh(MESHDIR"sphere.obj");
	sphere->SetTexture(SOIL_load_OGL_texture(TEXTUREDIR"sun.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, 0));
	sphere->SetTextureAndBumpmapRepeat(true);

	sun = new SceneNode(sphere, Vector4(1.0f, 1.0f, 1.0f, 1.0f));
	sun->SetModelScale(Vector3(50.0f, 50.0f, 50.0f));
	sun->SetTransform(Matrix4::Translation(worldLight->GetPosition()));

	return sun != NULL;
}

/* Method used to initialize all the shaders for use later during runtime
* Return: boolean type that shows if initialization is successful
* Parameters: None
* Author: Kan Tang
*/
bool Renderer::InitializeShaders(){
	//The first step of initializing shaders are to empty the vectors
	shaders.clear();
	//Then push back each of the shaders into the shaders vector.
	//push back the SIMPLESHADER
	shaders.push_back(new Shader(SHADERDIR"TechVertex.glsl", SHADERDIR"TechFragment.glsl"));
	//push back the PERPIXELSHADER
	shaders.push_back(new Shader(SHADERDIR"PerPixelVertex.glsl", SHADERDIR"PerPixelFragment.glsl"));
	//push back the BUMPSHADER
	shaders.push_back(new Shader(SHADERDIR"BumpVertex.glsl", SHADERDIR"BumpFragment.glsl"));
	//shader for 1st pass of shadow rendering, SHADOWSHADER
	shaders.push_back(new Shader(SHADERDIR"shadowVert.glsl", SHADERDIR"shadowFrag.glsl"));
	//push back the SHADOWSCENESHADER, use this to generate scene after shadow
	shaders.push_back(new Shader(SHADERDIR"shadowSceneVert.glsl", SHADERDIR"shadowSceneFrag.glsl"));
	//push back the POSTSHADER
	shaders.push_back(new Shader(SHADERDIR"processVertex.glsl", SHADERDIR"processFrag.glsl"));
	//push back the REFLECTSHADER
	shaders.push_back(new Shader(SHADERDIR"ReflectVertex.glsl", SHADERDIR"ReflectFragment.glsl"));
	//after that link all the shaders, if anything is wrong return false.
	for (unsigned int i = 0; i < MAXSHADERCOUNT; ++i)
	{
		if (!shaders[i]->LinkProgram())
			return false;
	}

	//after all the shaders are succesfully linked, return true.
	return true;
}

/* Method used to generate shadow texture buffer and the frame buffer object for shadow
* Return: boolean type that shows if generating buffer object is successful
* Parameters: None
* Author: Kan Tang
*/
bool Renderer::GenerateShadowBuffer()
{
	glGenTextures(1, &shadowTex);
	glBindTexture(GL_TEXTURE_2D, shadowTex);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOWSIZE, SHADOWSIZE, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);

	glBindTexture(GL_TEXTURE_2D, 0);

	glGenFramebuffers(1, &shadowFBO);

	glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowTex, 0);

	glDrawBuffer(GL_NONE);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	return true;
}

void Renderer::UpdateScene(float msec)	{

	if(!HUDManager::GetInstance()->GetPaused() && HUDManager::GetInstance()->GetRunning())
	{

		if(camera) {
			camera->UpdateCamera(msec); 
		}
		//codes below are for debugging
		angle += (msec);
		angle = angle > 3600000.0f ? angle - 3600000.0f: angle;
		worldLight->SetPosition(WORLD_LIGHT_STARTING_POSITION + Vector3(cos(angle / 10000.0f) * 1000.0f, 0, sin(angle / 10000.0f) * 1000.0f));
		sun->SetTransform(Matrix4::Translation(worldLight->GetPosition()));
		sun->Update(msec);
		root->Update(msec);

		/*if (Window::GetKeyboard()->KeyRelease(APPLY_BLUR))
		{
			isBlurred = false;
		}else
		{
			isBlurred = true;
		}*/
		/*if (Window::GetKeyboard()->KeyRelease(APPLY_FOG))
		{
			isFog = false;
		}
		else
		{
			isFog = true;
		}*/
	}
}

void Renderer::RenderScene()	{	
	
	for(int i=0;i<2 && camera;i++)				//draw two times, fist for inversed image, second for normal image
	{
		if(i==0)
		{
			isInversed = true;
			glBindFramebuffer(GL_FRAMEBUFFER, bufferFBO[REFLECTSCENE]);				//put all inversed image into reflectbuffer
			glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
		}else
		{
			isInversed = false;
			//glBindFramebuffer(GL_FRAMEBUFFER, bufferFBO[MAINSCENE]);				//put all normal image into mainbuffer
			glBindFramebuffer(GL_FRAMEBUFFER, bufferFBO[MAINSCENE]);
		}

		modelMatrix.ToIdentity();
		viewMatrix = camera->BuildViewMatrix();
		projMatrix = Matrix4::Perspective(zNear, zFar, (float)width / (float)height, 45.0f);
		//frameFrustum.FromMatrix(projMatrix * viewMatrix);
		glEnable(GL_DEPTH_TEST);
		glDisable(GL_CULL_FACE);
		//glDisable(GL_STENCIL_TEST);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		DrawWorldLight();
		DrawShadowScene();
		DrawCombinedScene();
		
		if(i==0)
		{
			glBindFramebuffer(GL_FRAMEBUFFER, bufferFBO[WATERSCENE]);				//put water into waterbuffer
			glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
			DrawWater();

			glBindFramebuffer(GL_FRAMEBUFFER,bufferFBO[MAINSCENE]);					//add water,inversed image to mainbuffer
			glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
			SetCurrentShader(shaders[REFLECTSHADER]);
			glDisable(GL_DEPTH_TEST);
			projMatrix = Matrix4::Orthographic(-1, 1, 1, -1, -1, 1);
			viewMatrix.ToIdentity();
			modelMatrix.ToIdentity();
			UpdateShaderMatrices();

			glUniform1i(glGetUniformLocation(currentShader->GetProgram(),
				"sceneTex"), 3);
			glActiveTexture(GL_TEXTURE3);
			glBindTexture(GL_TEXTURE_2D, bufferColourTex[REFLECTSCENE]);

			glUniform1i(glGetUniformLocation(currentShader->GetProgram(),
				"reflectOffset"), 4);
			glActiveTexture(GL_TEXTURE4);
			glBindTexture(GL_TEXTURE_2D, offSetTex);

			quad->SetTexture(bufferColourTex[WATERSCENE]);
			quad->Draw();
			glUseProgram(0);
			glEnable(GL_DEPTH_TEST);
		}
	}
	//TODO: add bloom code here
	//the buffer is going to be the one called bufferFBO[MAINSCENE]
	DrawPostProcess();										//draw all post effects
	DrawHUD();

		// ------ Added by Monica --------------- //
	if (TerrainClass::RESTART_TERRAIN) {
		glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);;
		TerrainClass::RESTART_TERRAIN = false;
	}
	// ------------------------------------------ // 

	glUseProgram(0);
	SwapBuffers();
}


/* Modified for either using bumpmap/texture or not.
* Modified by Kan
*/
void	Renderer::DrawNode(SceneNode*n)	{
	if(n->GetMesh()) {
		modelMatrix = n->GetWorldTransform() * Matrix4::Scale(n->GetModelScale());
		glUniformMatrix4fv(glGetUniformLocation(currentShader->GetProgram(), "modelMatrix"), 1, false, (float*)&modelMatrix.values);

		Matrix4 tempMatrix = shadowMatrix * modelMatrix;
		glUniformMatrix4fv(glGetUniformLocation(currentShader->GetProgram(), "shadowMatrix"), 1, false, *&tempMatrix.values);
		glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "isInversed"), (int)isInversed);

		glUniform4fv(glGetUniformLocation(currentShader->GetProgram(), "nodeColour"),1,(float*)&n->GetColour());
		if (n->GetMesh()->GetTexture() > 0)
		{
			glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "useTexture"), 1);
		}
		else
		{
			glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "useTexture"), 0);
		}
		if (n->GetMesh()->GetBumpMap() > 0)
		{
			glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "useBumpmap"), 1);
		}
		else
		{
			glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "useBumpmap"), 0);
		}
		n->Draw(*this);
	}
}

void	Renderer::BuildNodeLists(SceneNode* from)	{
	Vector3 direction = from->GetWorldTransform().GetPositionVector() - camera->GetPosition();
	from->SetCameraDistance(Vector3::Dot(direction,direction));

	//if(frameFrustum.InsideFrustum(*from)) {
	if(from->GetColour().w < 1.0f) {
		transparentNodeList.push_back(from);
	}
	else{
		nodeList.push_back(from);
	}
	//}

	for(vector<SceneNode*>::const_iterator i = from->GetChildIteratorStart(); i != from->GetChildIteratorEnd(); ++i) {
		BuildNodeLists((*i));
	}
}

void	Renderer::DrawNodes()	 {
	for(vector<SceneNode*>::const_iterator i = nodeList.begin(); i != nodeList.end(); ++i ) {
		DrawNode((*i));
	}

	for(vector<SceneNode*>::const_reverse_iterator i = transparentNodeList.rbegin(); i != transparentNodeList.rend(); ++i ) {
		DrawNode((*i));
	}
}

/* Method used to set the shader to simple shader and draw the sun. Restore the shader after the light has been drawn
* Return: None
* Parameters: None
* Author: Kan Tang
*/
void Renderer::DrawWorldLight(){
	Shader* tempShader = currentShader;
	SetCurrentShader(shaders[SIMPLESHADER]);
	textureMatrix.ToIdentity();
	UpdateShaderMatrices();
	if (sun->GetMesh()) {
		glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "diffuseTex"), 0);
		glUniformMatrix4fv(glGetUniformLocation(currentShader->GetProgram(), "modelMatrix"), 1, false, (float*)&(sun->GetWorldTransform()*Matrix4::Scale(sun->GetModelScale())));
		glUniform4fv(glGetUniformLocation(currentShader->GetProgram(), "nodeColour"), 1, (float*)&sun->GetColour());
		glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "isInversed"), (int)isInversed);
		if (sun->GetMesh()->GetTexture() > 0)
		{
			glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "useTexture"), 1);
		}
		else
		{
			glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "useTexture"), 0);
		}
		sun->Draw(*this);
	}
	if (tempShader)
	{
		SetCurrentShader(tempShader);
	}
}

void	Renderer::SortNodeLists()	{
	std::sort(transparentNodeList.begin(),	transparentNodeList.end(),	SceneNode::CompareByCameraDistance);
	std::sort(nodeList.begin(),				nodeList.end(),				SceneNode::CompareByCameraDistance);
}

void	Renderer::ClearNodeLists()	{
	transparentNodeList.clear();
	nodeList.clear();
}

void	Renderer::SetCamera(Camera*c) {
	camera = c;
}

void	Renderer::AddNode(SceneNode* n) {
	root->AddChild(n);
}

void	Renderer::RemoveNode(SceneNode* n) {
	root->RemoveChild(n);
}

/* Water stuff
* Author: Aaron
*/
void Renderer::DrawWater()
{
	Matrix4 tmpmodel = modelMatrix;
	Matrix4 tmptexture = textureMatrix;
	SetCurrentShader(shaders[PERPIXELSHADER]);
	SetShaderLight(*worldLight);
	modelMatrix = Matrix4::Translation(Vector3(-7500, -500, -3000))*Matrix4::Scale(Vector3(15000, 10000, 15000)) * Matrix4::Rotation(-90, Vector3(1, 0, 0));
	textureMatrix.ToIdentity();
	UpdateShaderMatrices();
	wavesQuad->Draw();
	glUseProgram(0);
	modelMatrix = tmpmodel;
	textureMatrix = tmptexture;
}
/* Create buffers
* Author: Aaron
*/
void Renderer::InitBuffers()
{
	quad = Mesh::GenerateQuad();
	isBlurred = false;
	isInversed = false;

	GLenum buffers[2];
	buffers[0] = GL_COLOR_ATTACHMENT0;
	buffers[1] = GL_COLOR_ATTACHMENT1;

	for(int i=0;i<MAXSCENECOUNT;i++)
	{
		GenerateScreenTexture(bufferColourTex[i]);
		GenerateScreenTexture(bufferDepthTex[i],true);
		if(i==WATERSCENE){GenerateScreenTexture(offSetTex);}

		glGenFramebuffers(1, &bufferFBO[i]);
		glBindFramebuffer(GL_FRAMEBUFFER, bufferFBO[i]);
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
			GL_TEXTURE_2D,bufferColourTex[i], 0);
		if(i==WATERSCENE){glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
			GL_TEXTURE_2D, offSetTex, 0);}
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
			GL_TEXTURE_2D, bufferDepthTex[i], 0);
		if(i==WATERSCENE){glDrawBuffers(2, buffers);}
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
	}
}

/*All post processing
* Author: Aaron
* Add fog effect by Matrix
*/
void Renderer::DrawPostProcess()
{
	glBindFramebuffer(GL_FRAMEBUFFER , 0);
	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
	SetCurrentShader(shaders[POSTSHADER]);
	glDisable(GL_DEPTH_TEST);
	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "isBlur"), isBlurred);
	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "isFog"), isFog);
	glUniform1f(glGetUniformLocation(currentShader->GetProgram(), "fDensity"), Density);
	glUniform4fv(glGetUniformLocation(currentShader->GetProgram(), "vFogColor"), 1, (float*)&fogColor);

	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "depthTex"), 2);
	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, bufferDepthTex[MAINSCENE]);
	//glBindTexture(GL_TEXTURE_2D, bufferDepthTex[REFLECTSCENE]);

	projMatrix = Matrix4 :: Orthographic (-1 ,1 ,1 , -1 , -1 ,1);
	viewMatrix.ToIdentity ();
	modelMatrix.ToIdentity();
	textureMatrix.ToIdentity();
	UpdateShaderMatrices ();
	quad->SetTexture(bufferColourTex[MAINSCENE]);
	//quad->SetTexture(bufferColourTex[REFLECTSCENE]);
	quad ->Draw();
	glUseProgram (0);
	glEnable(GL_DEPTH_TEST);
}
/*PostProcessing
* Author: Matrix
*/
//void Renderer::DrawFog(){
//
//	glBindFramebuffer(GL_FRAMEBUFFER, 0);
//	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
//	SetCurrentShader(shaders[POSTSHADER]);
//
//	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "depthTex"), 4);
//	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "diffuseTex"), 0);
//	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "isFog"), 1);
//	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "isBlur"), 0);
//
//	glUniform1f(glGetUniformLocation(currentShader->GetProgram(), "fDensity"), Density);
//	glUniform4fv(glGetUniformLocation(currentShader->GetProgram(), "vFogColor"), 1, (float*)&fogColor);
//
//	projMatrix = Matrix4::Orthographic(-1, 1, 1, -1, -1, 1);
//	viewMatrix.ToIdentity();
//	modelMatrix.ToIdentity();
//	UpdateShaderMatrices();
//	glActiveTexture(GL_TEXTURE4);
//	glBindTexture(GL_TEXTURE_2D, bufferDepthTex);
//	quad->SetTexture(bufferColourTex);
//	quad->Draw();
//	glUseProgram(0);
//}

void Renderer::GenerateScreenTexture(GLuint & into, bool depth)
{
	glGenTextures(1, &into);
	glBindTexture(GL_TEXTURE_2D, into);

	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	glTexImage2D(GL_TEXTURE_2D, 0,
		depth ? GL_DEPTH_COMPONENT24 : GL_RGBA8,
		width, height, 0,
		depth ? GL_DEPTH_COMPONENT : GL_RGBA,
		GL_UNSIGNED_BYTE, NULL);

	glBindTexture(GL_TEXTURE_2D, 0);
}

void Renderer::DrawShadowScene()
{
	glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
	glClear(GL_DEPTH_BUFFER_BIT);

	glViewport(0, 0, SHADOWSIZE, SHADOWSIZE);

	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

	SetCurrentShader(shaders[SHADOWSHADER]);

	projMatrix = Matrix4::Perspective(SHADOWZNEAR, 15000.0f, (float)width / (float)height, WORLD_LIGHT_VIEWANGLE);
	viewMatrix = Matrix4::BuildViewMatrix(worldLight->GetPosition(), WORLD_LIGHT_DIRECTION);
	shadowMatrix = biasMatrix*(projMatrix*viewMatrix);
	UpdateShaderMatrices();

	BuildNodeLists(root);
	SortNodeLists();
	DrawNodes();

	glUseProgram(0);
	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	glViewport(0, 0, width, height);

	projMatrix = Matrix4::Perspective(zNear, zFar, (float)width / (float)height, 45.0f);
}

void Renderer::DrawCombinedScene()
{
	if(isInversed)
	{
		glBindFramebuffer(GL_FRAMEBUFFER , bufferFBO[REFLECTSCENE]);
	}else
	{
		glBindFramebuffer(GL_FRAMEBUFFER , bufferFBO[MAINSCENE]);
	}	

	SetCurrentShader(shaders[SHADOWSCENESHADER]);
	

	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "diffuseTex"), 0);
	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "bumpTex"), 1);
	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "shadowTex"), 2);

	glUniform3fv(glGetUniformLocation(currentShader->GetProgram(), "cameraPos"), 1, (float*)&camera->GetPosition());

	SetShaderLight(*worldLight);

	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, shadowTex);

	viewMatrix = camera->BuildViewMatrix();
	UpdateShaderMatrices();


	if(HUDManager::GetInstance()->GetRunning())
	{
		DrawNodes();
	}

	ClearNodeLists();
	glUseProgram(0);
}

/* Method used to generate Lensflare buffer
* Return: None
* Parameters: None
* Author: Kan Tang
*/
void Renderer::InitializeLensFlareBuffer()
{

}


////////////////////HUD STUFF/////////////////////////////////////

void Renderer::DrawHUD()
{
	glDisable(GL_CULL_FACE);
	//Set drawing to orthographic with simple shader
	SetCurrentShader(shaders[SIMPLESHADER]);
	//set perspective to orthographic
	viewMatrix.ToIdentity();
	projMatrix = Matrix4::Orthographic(-1.0f,1.0f,(float)width, 0.0f,(float)height, 0.0f);
	//	frameFrustum.FromMatrix(projMatrix * viewMatrix);
	UpdateShaderMatrices();

	//Get Hud lists
	vector<SceneNode*> HUDlist = HUDManager::GetInstance()->GetDrawList();
	vector<string> HighScorelist = HUDManager::GetInstance()->GetHighScoreText();

	//Draw Hud Objects
	for(vector<SceneNode*>::iterator it = HUDlist.begin(); it != HUDlist.end(); it++)
	{
		DrawNode((*it));
	}


	int position = 240;
	for(vector<string>::iterator it = HighScorelist.begin(); it != HighScorelist.end(); it++)
	{
		DrawText((*it), Vector3(width - 350,position,0), 16.0f);
		position += 30;
	}

	if(HUDManager::GetInstance()->GetRunning())
	{
		//draw time
		//Draw HighScore

		DrawText("Time: " + std::to_string(HUDManager::GetInstance()->GetGameTime()), Vector3((1280/2)-100,60,0), 16.0f);

		//Draw Debug Text
		if(HUDManager::GetInstance()->GetDebugMode())
		{
			//Draw FPS if in debug mode
			DrawText("Renderer FPS: " + std::to_string(HUDManager::GetInstance()->GetRenderFPS()), Vector3(10,height-100,0), 16.0f);
			DrawText("Physics FPS: " + std::to_string(HUDManager::GetInstance()->GetPhysicsFPS()/100000), Vector3(10,height-50,0), 16.0f);
		}
	}


	//Set perspective back to normal
	viewMatrix = camera->BuildViewMatrix();

	projMatrix = Matrix4::Perspective(zNear,zFar,(float)width / (float) height, 45.0f);
	//	frameFrustum.FromMatrix(projMatrix * viewMatrix);
	UpdateShaderMatrices();

	glEnable(GL_CULL_FACE);
}

void Renderer::DrawHudNodes(SceneNode* hudroot)
{
	DrawNode(hudroot);

	for(vector<SceneNode*>::const_iterator it = hudroot->GetChildIteratorStart(); it != hudroot->GetChildIteratorEnd(); it++)
	{
		DrawHudNodes((*it));
	}
}


void	Renderer::AddHUDNode(SceneNode* n) {
	root->AddChild(n);
}

void	Renderer::RemoveHUDNode(SceneNode* n) {
	root->RemoveChild(n);
}

void Renderer::DrawText(const std::string &text, const Vector3 &position, const float size, const bool perspective)	{

	//Create a new temporary TextMesh, using our line of text and our font
	TextMesh* mesh = new TextMesh(text,*basicFont);
	SceneNode temp(mesh);

	glBlendFunc(GL_SRC_ALPHA, GL_ONE);

	//This just does simple matrix setup to render in either perspective or
	//orthographic mode, there's nothing here that's particularly tricky.
	if(perspective) {
		modelMatrix = Matrix4::Translation(position) * Matrix4::Scale(Vector3(size,size,1));

	}
	else{	
		//In ortho mode, we subtract the y from the height, so that a height of 0
		//is at the top left of the screen, which is more intuitive
		//(for me anyway...)
		temp.SetModelScale(Vector3(size,size,1));
		temp.SetTransform(Matrix4::Translation(Vector3(position.x,height-position.y, position.z)));
		temp.Update(0.0f);

	}

	DrawNode(&temp);

	delete mesh; //Once it's drawn, we don't need it anymore!

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

}
